#!/bin/sh

#trap goodbye INT HUP

usage() {
	echo "Smail v0.1.0: Send or read emails from your terminal."
	echo ""
	echo "Usage: smail [options] [command]"
	echo ""
	echo "Options:"
	echo "  -v		verbose output"
	echo "  -h		show this help"
	echo "  --help		show this help"
	echo "  --version	show version info"
	echo ""
	echo "Commands:"
	echo "  send		runs the send email interface"
	echo "  read		runs the read email CLI, default"
	echo "  config		runs the configuration script, also on first run"
	echo "  help		show this help"
	echo ""
	echo "Examples:"
	echo "  smail config	Run the configuration script"
	echo "  smail		Read emails"
	echo ""
	echo "Report bugs to: bleemayer@gmail.com"
	echo "Home page: <https://www.github.com/blmayer/smail/>"
	echo "General help: <https://www.github.com/blmayer/smail/wiki>"
}

show_version() {
	echo "smail 0.1.0"
	echo "Copyright (C) 2020 Brian Mayer."
	echo "License MIT: MIT License <https://opensource.org/licenses/MIT>"
	echo "THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,"
	echo "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF"
	echo "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT."
	echo ""
	echo "Written by Brian Lee Mayer."
}

goodbye() {
	[ -e "$debug" ] || echo Quitting
	case $state in
		1|2|3|6|7|8)
			[ -e "$debug" ] || echo "Sending quit command"
			echo rset > .rcvsmtp
			echo quit > .rcvsmtp
			;;
		4|5)
			[ -e "$debug" ] || echo "Dropping and sending quit command"
			echo "" > .rcvsmtp
			echo rset > .rcvsmtp
			echo quit > .rcvsmtp
			;;
		9)
			[ -e "$debug" ] || echo "Erasing .temp and sending quit command"
			rm .temp
			echo rset > .rcvsmtp
			echo quit > .rcvsmtp
			exit 3
			;;
		10)
			echo quit > .rcvsmtp
			;;
		*)
			exit 2
			;;
	esac

	rm .rcvsmtp .txsmtp
	exit 0
}

read_opts() {
	for arg in "$@"
	do
		case $arg in
			"-v")
				debug=1
				;;
			"-h" | "help" | "--help")
				usage
				exit 0
				;;
			"--version")
				show_version
				exit 0
				;;
			"send")
				op="send"
				;;
			"read")
				op="read"
				;;
			"config")
				configure
				exit 0
				;;
			"")
				break
				;;
			*)
				echo "Unrecognized option $arg"
				usage
				exit 1
				;;
		esac
	done
}

configure() {
	echo "Running configuration"
	[ -e "$HOME/.config/smail" ] || mkdir -p "$HOME/.config/smail"

	echo "Enter email:"
	read -r username
	echo "email=$(echo "$username" | base64 )" > "$configfile"

	echo "Enter password:"
	stty -echo
	read -r password
	stty echo
	echo "password=$(echo "$password" | base64 )" >> "$configfile"

	echo "Enter your favorite editor: [vi]"
	# shellcheck disable=SC2039
	read -re editor
	echo "editor=${editor:-vi}" >> "$configfile"
	echo Done
}

connect_smtp() {
	openssl s_client -quiet \
		-starttls smtp \
		-connect smtp.gmail.com:587 \
		-crlf < .rcvsmtp > .txsmtp 2> /dev/null &
	state=1

	[ -e $debug ] || echo "Sending client hello"
	echo ehlo smtp.gmail.com > .txsmtp
	state=2
}

add_attachments() {
	echo "Enter file path:"
	# shellcheck disable=SC2039,SC2162
	read -e annex
	if [ -f "$annex" ]; then
		echo "Enter attachment name: [$(basename "$annex")]"
		read -r annexname
		[ "$annexname" = "" ] && annexname="$(basename "$annex")"

		{
			echo "Content-Type: application/octet-stream"
			echo "Content-Transfer-Encoding: base64"
			echo "Content-Disposition: attachment;"
			echo " filename= \"$annexname\""
			echo ""
		} >> .temp
		base64 "$annex" >> .temp
		[ -e $debug ] || echo "Added $annex with name: $annexname"
	else
		echo "ERROR: File not found!"
	fi

	echo "Add another attachment(s)? [y/N]"
	read -r another
	[ "$another" = "y" ] && { echo "--$1" >> .temp; add_attachments "$1"; }
}

get_rcpt() {
	echo "$to" | cut -d ',' -f "$1"
}

compose() {
	echo "Type recipient(s) (comma separated):"
	read -r to

	echo "To: $to" > .temp
	echo "From: $emaildec" >> .temp

	echo "Type Cc(s): (comma separated)"
	read -r cc
	[ -n "$cc" ] && { echo "Cc: $cc" >> .temp; to="$to,$cc"; }

	echo "Type Cco(s): (comma separated)"
	read -r cco
	[ -n "$cco" ] && { echo "Cco: $cco" >> .temp; to="$to,$cco"; }

	# Transform into list for sending later
	n=$(($(echo "$to" | tr -d -c ',' | wc -c | xargs) + 1))

	echo "Type subject:"
	read -r subj
	echo "Subject: $subj" >> .temp
	[ -e $debug ] || echo "Email fields:"
	[ -e $debug ] || cat .temp

	boundary="$(date | tr " :-" "wUX")"
	{
		echo "MIME-Version: 1.0"
		echo "Content-Type: multipart/mixed;"
		echo " boundary= \"$boundary\""
		echo ""
	
		echo "--$boundary"
		echo 'Content-Type: text/plain; charset=US-ASCII'
		echo ""
	} >> .temp

	$editor .body
	sed 's/^.$/../' .body | fold -w 72 -s >> .temp
	[ -e $debug ] || echo "Email body:"
	[ -e $debug ] || cat .body
	rm .body

	echo "" >> .temp
	echo "--$boundary" >> .temp

	echo "Insert attachment(s)? [y/N]"
	read -r attach
	[ "$attach" = "y" ] && add_attachments "$boundary"

	echo "--$boundary--" >> .temp
}

retry() {
	echo Retrying...
	case $state in
		2)
			[ -e $debug ] || echo "Reconnecting..."
			echo ehlo smtp.gmail.com > .txsmtp
			;;
		3)
			[ -e $debug ] || echo "Logging in again..."
			echo auth login > .txsmtp
			;;
		4)
			[ -e $debug ] || echo "Resending email"
			echo "$email" > .txsmtp
			;;
		5)
			[ -e $debug ] || echo "Resending password"
			echo "$password" > .txsmtp
			;;
		6)
			[ -e $debug ] || echo "Resending mail command"
			echo 'mail from: <'"$emaildec"'>' > .txsmtp
			;;
		7)
			[ -e $debug ] || echo "Resending recipient"
			echo rcpt to: '<'"$to"'>' > .txsmtp
			;;
		8)
			[ -e $debug ] || echo "Resending data command"
			echo data > .txsmtp
			;;
		9)
			[ -e $debug ] || echo "Resending data"
			cat .temp > .txsmtp
			echo '.' > .txsmtp
			;;
	esac
}

loop_smtp() {
	while :
	do
		read -r msg < .rcvsmtp
		[ -e $debug ] || echo "received: $msg"
		case $msg in
			"221 2.0.0"*)
				retry
				;;

			"250-"*)
				;;

			"250 SMTPUTF8"*)
				[ -e $debug ] || echo logging in
				state=3
				echo auth login > .txsmtp
				;;

			"334 VXNlcm5hbWU6"*)
				[ -e $debug ] || echo sending email
				state=4
				echo "$email" > .txsmtp
				;;

			"334 UGFzc3dvcmQ6"*)
				[ -e $debug ] || echo sending password
				state=5
				echo "$password" > .txsmtp
				;;

			"235 2.7.0"*)
				[ -e $debug ] || { echo logged in; echo "$emaildec"; }
				state=6
				echo 'mail from: <'"$emaildec"'>' > .txsmtp
				;;

			"250 2.0.0"*)
				state=10
				rm .temp
				break
				;;

			"250 2.1.0"*)
				[ -e "$debug" ] || get_rcpt "$n"
				state=7
				echo rcpt to: '<'"$(get_rcpt $n)"'>' > .txsmtp
				n=$((n - 1))
				;;

			"250 2.1.5"*)
				if [ ! $n = 0 ]
				then
					[ -e $debug ] || get_rcpt "$n"
					echo rcpt to: '<'"$(get_rcpt $n)"'>' > .txsmtp
					n=$((n - 1))
				else
					[ -e $debug ] || echo data
					state=8
					echo data > .txsmtp
				fi
				;;

			"354  Go ahead"*)
				state=9
				cat .temp > .txsmtp
				echo '.' > .txsmtp
				;;

			"451 4.4.2 Timeout"*)
				[ -e $debug ] || echo "Connection closed"
				break
				;;

			"501 5.5.2 Cannot Decode response"*)
				state=3
				retry
				;;
			"502 5.5.1 Unrecognized command"*)
				retry
				;;
			"503 5.5.1 MAIL first"*)
				state=6
				retry
				;;
			"530-5.7.0"*)
				;;
			"530 5.7.0"*)
				state=3
				retry
				;;
			"535 5.7.8"*)
				state=3
				retry
				;;
			"553 5.1.3"*)
				retry
				;;
			"554 5.7.0"*)
				break
				;;
			"555 5.5.2 Syntax error"*)
				echo FATAL ERROR email not sent
				break
				;;
			*)
				[ -e $debug ] || echo "Unrecognized message"
				break
				;;
		esac
	done
}

### ---- IMAP Stuff ------------------------------------------------ ###

send_imap() {
	seq="$(printf '%d' $((seq+1)))"

	[ -e $debug ] || echo "Sending: a$seq $@"
	echo "a$seq $@" > .tximap
}


connect_imap() {
	openssl s_client -quiet -connect imap.gmail.com:993 \
		-crlf < .tximap > .rcvimap 2> /dev/null &
	state=1
	seq=1
}

auth_imap() {
	[ -e $debug ] || echo "Authenticating"
	send_imap "login $emaildec $passworddec"
	state=1

	[ -e $debug ] || echo reading
	while read -r msg
	do
		[ -e $debug ] || echo "received: $msg"
		case "$msg" in
			"a$seq OK"*)
				state=2
				break
				;;
			"a$seq BAD LOGIN"*)
				state=-1
				break
				;;
		esac
	done < .rcvimap
}

loop_imap() {
	while :
	do
		[ -e $debug ] || echo "In state $state"
		case $state in
			1)
				auth_imap
				;;
			2)
				select_inbox
				;;
			3)
				fetch_unseen
				;;
			4)
				read_command
				;;
			5)
				break
				;;
			-1)
				echo "Error logging in, try again later"
				break
				;;
			*)
				[ -e $debug ] || echo "Unrecognized state"
				;;
		esac
	done
}

retry_imap() {
	case "$state" in
		2)
			select_inbox
			;;
	esac
}

select_inbox() {
	[ -e $debug ] || echo "Selecting inbox"
	send_imap "select inbox"

	[ -e $debug ] || echo reading
	while read -r msg
	do
		[ -e $debug ] || echo "received: $msg"
		case "$msg" in
			"a$seq OK"*)
				state=3
				break
				;;
			"a$seq BAD"*)
				break
				;;
		esac
	done < .rcvimap
}

decode_utf8() {
	sed -e 's/.*=?[uU][tT][fF]-8?[Qq]?//g' -e 's/?=//g' \
	-e 's/=F0=9F=8F=AD=C2=A0/🏭/g' \
	-e 's/=C2=A0=F0=9F=91=87/👇/g' \
	-e 's/=e2=80=93/-/g' \
	-e 's/=E2=80=99/’/g' \
	-e 's/=C3=BA/ú/g' \
	-e 's/=C3=B5/õ/g' \
	-e 's/=C3=B4/ô/g' \
	-e 's/=C3=B3/ó/g' \
	-e 's/=C3=AD/í/g' \
	-e 's/=C3=A9/é/g' \
	-e 's/=C3=A7/ç/g' \
	-e 's/=C3=A3/ã/g' \
	-e 's/=C3=A1/á/g' \
	-e 's/=C3=A0/à/g' \
	-e 's/=3F/?/g' \
	-e 's/=2D/-/g' \
	-e 's/=2C/,/g' \
	-e 's/=20/ /g' \
	-e 's/=20/ /g' \
	-e 's/=20/ /g' \
	-e 's/=29/)/g' \
	-e 's/=28/(/g' \
	-e 's/=21/!/g' \
	-e 's/=20/ /g' \
	-e 's/\\r//g's <<< "$@"
}

print_headers() {
	while read -r msg
	do
		[ -e $debug ] || echo "received: $msg"
		case "$msg" in
		"a$seq OK"*)
			break
			;;
		'From:'*)
			from="${msg:6}"
			;;
		'Date:'*)
			date="${msg:6}"
			;;
		'Subject:'*)
			subj="${msg:9}"
			;;
		"a$seq BAD"*)
			break
			;;
		esac
	done < .rcvimap

	from="$(sed 's/ <.*>//' <<< "$from")"
	from="$(decode_utf8 $from)"
	date="${date:0:25}"
	subj="$(decode_utf8 $subj)"
	
	echo "$1\t$date\t\t$from\t\t$subj"
}

fetch_unseen() {
	[ -e $debug ] || echo "Fetching unread mail"
	send_imap "search unseen"

	# Read response
	[ -e $debug ] || echo "Reading response"
	while read -r msg
	do
		[ -e $debug ] || echo "received: $msg"
		case "$msg" in
			'* SEARCH'*)
				res="${msg:9}"
				;;
			"a$seq OK"*)
				break
				;;
			"a$seq BAD"*)
				return
				;;
		esac
	done < .rcvimap

	# Parsing response
	[ -e $debug ] || echo "Getting individual mails"
	echo "id		date received		from			subject"
	for mail in $res
	do
		[ -e $debug ] || echo "Sending: a$seq fetch $mail BODY.PEEK[HEADER]"
		send_imap "fetch $mail BODY.PEEK[HEADER]"
		print_headers "$mail"
	done
	state=4
}

read_command() {
	echo "Type command:"
	echo "1) search"
	echo "2) fetch"
	echo "3) quit"

	read -r comm
	case "$comm" in
		"1" | "search")
			echo "Type search:"
			read -r search
			send_imap "search $search"
			;;
		"3" | "quit")
			send_imap "LOGOUT"
			state=5
			;;
		*)
			echo "Not an option, type quit to quit"
			;;
	esac

	echo "reading"
	while read -r msg
	do
		[ -e $debug ] || echo "received: $msg"
	done < .rcvimap

	# [ -e $debug ] || echo "Getting individual mails"
	# for mail in $res
	# do
	# 	[ -e $debug ] || echo "Sending: a$seq fetch $mail BODY[TEXT]"
	# 	echo "a$seq fetch $mail BODY" > .tximap
	# 	while read -r msg
	# 	do
	# 		[ -e $debug ] || echo "received: $msg"
	# 		case "$msg" in
	# 				"a$seq OK"*)
	# 				break
	# 				;;
	# 			"a$seq BAD"*)
	# 				break
	# 				;;
	# 		esac
	# 	done < .rcvimap
	# 	inc_seq
	# done
}


# Read arguments
configfile="$HOME/.config/smail/smail.conf"
read_opts "$@"

# Configuration step
[ -e "$configfile" ] || configure

email=$(grep email "$configfile" | cut -d '=' -f 2,3)
emaildec=$(echo "$email" | base64 -d)
password=$(grep password "$configfile" | cut -d '=' -f 2,3)
passworddec=$(echo "$password" | base64 -d)
editor=$(grep editor "$configfile" | cut -d '=' -f 2)

[ -p .rcvsmtp ] || mkfifo .rcvsmtp;
[ -p .txsmtp ] || mkfifo .txsmtp;
[ -p .rcvimap ] || mkfifo .rcvimap;
[ -p .tximap ] || mkfifo .tximap;

state=0

case "$op" in 
	"send")
		connect_smtp
		loop_smtp
		;;

	"read" | "") 
		connect_imap
		loop_imap
	;;
esac

#goodbye
